﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Ploter;
using MathWorks.MATLAB.NET.Arrays;
using MathWorks.MATLAB.NET.Utility;

namespace Tosi
{
    class GraficPlot
    {
        private Ploter.Ploter Plot;
        private MWArray[] axes;
            
        private int StreetNr;
        private MWNumericArray[,] Street;
        private MWCharArray[] StreetName;

        private int JunctionNr;
        private MWNumericArray[,] Junction;
        private MWNumericArray[] JunctionHeat;
        private MWCharArray[] JunctionName;

        private int TrafficLightNr;
        private MWNumericArray[,] TrafficLight;
        private MWCharArray[] TrafficLightState;

        private int CarNr;
        private MWNumericArray[,] Car;

        private MWNumericArray xMin;
        private MWNumericArray xMax;
        private MWNumericArray yMin;
        private MWNumericArray yMax;

        private MWNumericArray Radius;
        private MWNumericArray Radius2;
        
        private MWNumericArray Angle;
        private double Angle1;
        
        private List<MWArray[]> changeList = null;

        public GraficPlot()
        {
            Plot = new Ploter.Ploter();
            axes = null;
            changeList = new List<MWArray[]>();
            
            Radius = 8; Radius2 = 10;
            Angle1 = 0.4; 
       
            xMin = 0; xMax = 1126;
            yMin = 0; yMax = 579;
            
        }
        public void LoadData(int n, double[,] injvkt, string[] injnam,
            int m, int[,] strvkt, string[] strnam)
        {
            JunctionNr = n;
            Junction = new MWNumericArray[JunctionNr, 2];
            JunctionName = new MWCharArray[JunctionNr];
            JunctionHeat = new MWNumericArray[JunctionNr];
            for (int i = 0; i < JunctionNr; i++)
            {
                Junction[i, 0] = injvkt[i, 0];
                Junction[i, 1] = injvkt[i, 1];
                JunctionName[i] = injnam[i];
                JunctionHeat[i] = 0;
                JunctionHeat[i] = i % 11 * 10;
            }
            int db1 = 0;
            for (int i = 0; i < m; i++)
            {
                db1 += strvkt[i, 2];
            }
            StreetNr = db1;
            Street = new MWNumericArray[StreetNr, 6];
            StreetName = new MWCharArray[StreetNr];
            TrafficLightNr = m;
            TrafficLight = new MWNumericArray[TrafficLightNr, 2];
            TrafficLightState = new MWCharArray[TrafficLightNr];
            int db = 0;
            for (int i = 0; i < m; i++)
            {
                int id1 = strvkt[i, 0];
                int id2 = strvkt[i, 1];
                int first = db;
                for (int j = 0; j < strvkt[i, 2]; j++)
                {
                    MWArray[] output1 = null;
                    Angle = Angle1 * (j + 1);
                    output1 = Plot.FindStreetPosition(6, Junction[id1, 0], Junction[id1, 1],
                        Junction[id2, 0], Junction[id2, 1], Radius, Angle);
                    Street[db, 0] = (MWNumericArray)output1[0];
                    Street[db, 1] = (MWNumericArray)output1[1];
                    Street[db, 2] = (MWNumericArray)output1[2];
                    Street[db, 3] = (MWNumericArray)output1[3];
                    Street[db, 4] = (MWNumericArray)output1[4];
                    Street[db, 5] = (MWNumericArray)output1[5];
                    StreetName[db] = (MWCharArray)strnam[i];
                    db++;
                }
                MWArray[] output2 = null;
                output2 = Plot.FindTLPosition(2, Street[first, 0], Street[first, 1],
                    Street[first, 2], Street[first, 3], Radius2);
                TrafficLight[i, 0] = (MWNumericArray)output2[0];
                TrafficLight[i, 1] = (MWNumericArray)output2[1];
                TrafficLightState[i] = "red";
            }
        }
        public void openFig()
        {
            axes = Plot.OpenFigure(2);
        }
        public void scaling()
        {
            Plot.AxesDim(axes[0], xMin, xMax, yMin, yMax);
            Plot.AxesDim(axes[1], xMin, xMax, yMin, yMax);
        }
        public void clearFig()
        {
            Plot.CloseFigure(axes[0]);
        }
        public void clearBack()
        {
            Plot.ClearAxes(axes[0]);
        }
        public void clearFront()
        {
            Plot.ClearAxes(axes[1]);
        }
        public void changeToBack()
        {
            Plot.ChangeAxes(axes[0]);
        }
        public void changeToFront()
        {
            Plot.ChangeAxes(axes[1]);
        }
        public void scale()
        {
            Plot.HeatScale(axes[0], 676, 0, 450, 70);
        }
        public void cars()
        {
            MWArray[] argin = new MWArray[3 * changeList.Count + 3 * JunctionNr + 2 * CarNr];
            for (int id = 0; id < changeList.Count; id++)
            {
                argin[3 * id + 0] = changeList[id][0];
                argin[3 * id + 1] = changeList[id][1];
                argin[3 * id + 2] = changeList[id][2];
            }
            int offset = changeList.Count * 3;
            for (int id = 0; id < JunctionNr; id++)
            {
                argin[offset + 3 * id + 0] = Junction[id, 0];
                argin[offset + 3 * id + 1] = Junction[id, 1];
                argin[offset + 3 * id + 2] = JunctionHeat[id];
            }
            offset = offset + JunctionNr * 3;
            for (int id = 0; id < CarNr; id++)
            {
                argin[offset + 2 * id + 0] = Car[id, 0];
                argin[offset + 2 * id + 1] = Car[id, 1];
            }
            Plot.PlotIteration(axes[0], axes[1], changeList.Count, JunctionNr, Radius, argin);
            changeList.Clear();
        }
        public void lights()
        {
            for (int id = 0; id < TrafficLightNr; id++)
            {
                Plot.PlotTraficLight(axes[0], TrafficLight[id, 0], TrafficLight[id, 1], TrafficLightState[id]);
            }
        }
        public void streets()
        {
            for (int i = 0; i < StreetNr; i++)
                Plot.PlotLine(Street[i, 0], Street[i, 1], Street[i, 2], Street[i, 3]);
        }
        public void juntionTemplate()
        {
            for (int i = 0; i < JunctionNr; i++)
                Plot.PlotCircle1(Junction[i, 0], Junction[i, 1], Radius);
        }
        public void junctionNames()
        {
            for (int i = 0; i < JunctionNr; i++)
                Plot.PlotNameCircle(Junction[i, 0], Junction[i, 1], JunctionName[i]);
        }
        public void setCarNr(int carnum)
        {
            CarNr = carnum;
            Car = new MWNumericArray[CarNr, 2];
        }
        public void setCar(int id, Point pos)
        {
            Car[id, 0] = pos.getX();
            Car[id, 1] = pos.getY();
        }
        public void setLight(int id, int state)
        {
            if (state == 0)
                TrafficLightState[id] = "green";
            else
                TrafficLightState[id] = "red";
            
            MWArray[] tl = new MWArray[3];
            tl[0] = TrafficLight[id, 0];
            tl[1] = TrafficLight[id, 1];
            tl[2] = TrafficLightState[id];

            changeList.Add(tl);

            //Plot.PlotTraficLight(axes[0], TrafficLight[id, 0], TrafficLight[id, 1], TLState);
        }
        public void setJunctionState(int id, double state)
        {
            JunctionHeat[id] = (int)state;
        }
        public double[] getJunctions(int id)
        {
            double[] ans = new double[2];
            ans[0] = (double)Junction[id, 0];
            ans[1] = (double)Junction[id, 1];
            return ans;
        }
        public Point[] getStreet(int id)
        {
            Point[] ans = new Point[2];
            ans[0] = new Point((double)Street[id, 0], (double)Street[id, 1]);
            ans[1] = new Point((double)TrafficLight[id, 0], (double)TrafficLight[id, 1]);
            return ans;
        }
        public double[] getStreetPhi(int id)
        {
            double[] ans = new double[2];
            ans[0] = Street[id, 4].ToScalarDouble(); //cosphi
            ans[1] = Street[id, 5].ToScalarDouble(); //sinphi
            return ans;
        }
    }
}
